package me.chyxion.spring.ext.codegen.services.support;

import java.text.DateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import me.chyxion.dao.mybatis.BaseMapper;
import me.chyxion.dao.mybatis.pagination.PageParam;
import me.chyxion.spring.ext.codegen.services.CodeGenerator;
import me.chyxion.spring.ext.codegen.services.CodeGenBaseTool;
import me.chyxion.spring.ext.codegen.services.CodeGenService;
import me.chyxion.spring.ext.models.BaseModel;
import me.chyxion.spring.ext.services.BaseService;
import me.chyxion.spring.ext.services.support.BaseServiceSupport;
import me.chyxion.spring.ext.stereotype.Mock;
import me.chyxion.spring.ext.test.ControllerTestTool;
import me.chyxion.spring.ext.test.MockMapper;
import me.chyxion.spring.ext.utils.WordUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @version 0.0.1
 * @since 0.0.1
 * @author Shaun Chyxion <br />
 * chyxion@163.com <br />
 * Oct 6, 2014 1:10:02 PM
 */
@Service
public class CodeGenServiceSupport implements CodeGenService {
	private static final Logger log = LoggerFactory.getLogger(CodeGenServiceSupport.class);

	@Autowired
	private CodeGenBaseTool baseTool;
	@Autowired
	private List<CodeGenerator> codeGen;

	/*
	 * (non-Javadoc)
	 * @see me.chyxion.spring.ext.codegen.services.CodeGenService#process(java.lang.String, java.lang.String, java.util.List, java.lang.String)
	 */
    @Override
    public void process(String module, String model, List<?> columns, String table, boolean createTable) {
    	String modelMinusName = WordUtils.joinCamelCase(model, "-").toLowerCase();
		String url = modelMinusName;
		String pkg = baseTool.getGroupId();
		if (StringUtils.isNotBlank(module)) {
			url = module + "/" + url;
			pkg += "." + module;
		}
		else {
			module = "";
		}

    	@SuppressWarnings("unchecked")
        List<Map<String, Object>> cols = (List<Map<String, Object>>) columns;
    	model = StringUtils.capitalize(model);
		Map<String, Object> fmDataModel = new HashMap<String, Object>();
    	fmDataModel.put("createTable", createTable);
    	fmDataModel.put("table", table);
    	fmDataModel.put("notNull", false);
    	fmDataModel.put("notBlank", false);
    	for (Map<String, Object> col : cols) {
    		String rawName = (String) col.get("name");
    		String name = "";
    		for (String it : rawName.split("_")) {
    			name += StringUtils.capitalize(it);
    		}
    		col.put("rawName", rawName);
    		col.put("Name", name);
    		col.put("name", StringUtils.uncapitalize(name));
    		col.put("col", WordUtils.joinCamelCase(name, "_").toLowerCase());
    		if ((Boolean)col.get("notNull")) {
    			if ("String".equals(col.get("javaType"))) {
    				fmDataModel.put("notBlank", true);
    			}
    			else {
    				fmDataModel.put("notNull", true);
    			}
    		}
        }
    	fmDataModel.put("cols", cols);
    	fmDataModel.put("url", url);
    	fmDataModel.put("pkg", pkg);
    	fmDataModel.put("pkgDir", pkg.replace('.', '/'));
    	fmDataModel.put("modelFullName", pkg + "." + model);
		fmDataModel.put("module", module);
		fmDataModel.put("ModelName", model);
		fmDataModel.put("modelName", StringUtils.uncapitalize(model));
		fmDataModel.put("model_name", modelMinusName);
    	// super classes name
    	fmDataModel.put("baseServiceName", BaseService.class.getSimpleName());
    	fmDataModel.put("baseServiceFullName", BaseService.class.getName());
    	fmDataModel.put("baseServiceSupportName", BaseServiceSupport.class.getSimpleName());
    	fmDataModel.put("baseServiceSupportFullName", BaseServiceSupport.class.getName());
    	fmDataModel.put("baseModelName", BaseModel.class.getSimpleName());
    	fmDataModel.put("baseModelFullName", BaseModel.class.getName());
    	fmDataModel.put("baseMapperName", BaseMapper.class.getSimpleName());
    	fmDataModel.put("baseMapperFullName", BaseMapper.class.getName());
    	fmDataModel.put("mockMapperName", MockMapper.class.getSimpleName());
    	fmDataModel.put("mockMapperFullName", MockMapper.class.getName());
    	fmDataModel.put("mockName", Mock.class.getSimpleName());
    	fmDataModel.put("mockFullName", Mock.class.getName());
    	fmDataModel.put("pageParamName", PageParam.class.getSimpleName());
    	fmDataModel.put("pageParamFullName", PageParam.class.getName());
    	fmDataModel.put("ctrlrTestToolName", ControllerTestTool.class.getSimpleName());
    	fmDataModel.put("ctrlrTestToolFullName", ControllerTestTool.class.getName());
    	// Object Doc
    	Map<String, Object> objDocModel = new HashMap<String, Object>();
    	// time now
		objDocModel.put("now", 
			DateFormat.getDateTimeInstance(DateFormat.DEFAULT, 
				DateFormat.DEFAULT, Locale.US).format(new Date()));
		// code doc
    	fmDataModel.put("objDoc", 
    		baseTool.renderFtl("/codegen/obj-doc.ftl", objDocModel));
    	List<String> files = new LinkedList<String>();
    	for (CodeGenerator gen : codeGen) {
    		files.addAll(
    			Arrays.asList(
    				gen.process(fmDataModel, module, model)
    					.split(";")));
        }
    	log.debug("Save Code Generated Data, Module [{}], Model [{}].", module, model);
    	Map<String, Object> mapRec = new HashMap<String, Object>();
    	mapRec.put("cols", columns);
    	mapRec.put("module", module);
    	mapRec.put("model", model);
    	mapRec.put("files", files);
    	mapRec.put("table", table);
    	baseTool.saveRecord(mapRec);
    }

	/* (non-Javadoc)
	 * @see me.chyxion.spring.ext.codegen.services.CodeGenService#list()
	 */
	@Override
	public List<?> list() {
		List<Map<String, Object>> items = baseTool.listAll();
		for (Map<String, Object> item : items) {
			String text = (String) item.get("model");
			String module = (String) item.get("module");
			if (StringUtils.isNotBlank(module)) {
				text = module + "/" + text;
			}
			item.put("text", text);
			item.put("checked", false);
			item.put("leaf", true);
			item.remove("files");
		}
		return items;
	}

	/* (non-Javadoc)
	 * @see me.chyxion.spring.ext.codegen.services.CodeGenService#delete(java.util.List)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public void delete(List<?> items, boolean dropTable) {
		for (Map<String, Object> item : (List<Map<String, Object>>) items) {
			baseTool.deleteRec((String) item.get("module"), (String) item.get("model"), dropTable);
		}
	}
}
